/*
    Flood is a program to test the cut method on soft constraints problems
    Copyright (C) 2011  Mattia Gamba

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/


#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "generator.h"


MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connect(ui->generate, SIGNAL(clicked()), this, SLOT(genRequest()));
    connect(ui->clearProblems, SIGNAL(clicked()), this, SLOT(clearProblems()));
    connect(ui->solveproblem, SIGNAL(clicked()), this, SLOT(solveProblems()));
    connect(ui->actionQuit, SIGNAL(triggered()),this, SLOT(exit()));
}

void MainWindow::genRequest(){
    clearProblems();
    QVector<Parameters * > test_data;
    int steps = 0;

    if(ui->tighstep->isChecked())
        steps = (ui->maxtigh->value() - ui->tightness->value()) / ui->tightnessstep->value();
    else if(ui->denstep->isChecked())
        steps = (ui->maxden->value() - ui->density->value()) / ui->densitystep->value();

    QProgressBar progress;
    progress.setMaximum(((steps+1)*ui->instancesForProblem->value()));
    progress.show();
    for(int k = 0; k <= steps; k++){
        QVector<Problem *> group;
        for(int w = 0; w < ui->instancesForProblem->value(); w++){
            Parameters * pam = new Parameters(ui->n->text().toInt(),
                                              ui->m->text().toInt(),
                                              (ui->denstep->isChecked() ? ui->density->value() + (k*ui->tightnessstep->value()) : ui->density->value()),
                                              (ui->tighstep->isChecked() ? ui->tightness->value() + (k*ui->tightnessstep->value()) : ui->tightness->value()),
                                              ui->maxV->text().toFloat()
                                              );
            gen.setParameters(*pam);
            pm = gen.generate();
            group.push_back(pm);
            progress.setValue(((k)*ui->instancesForProblem->value()+(w+1)));
            //Debug
            //print(pm);
            test_data.push_back(pam);
        }

        test.push_back(group);
    }

    //Debug - print the last problem in a file
    //print(pm);

    while (!test_data.empty()) {
        delete test_data.back();  test_data.pop_back();
    }
    ui->generated->setText(QString().setNum(test.size()*ui->instancesForProblem->value()));
}

void MainWindow::clearProblems(){
    ui->generated->setText("0");
    for(int i = 0; i < test.size(); i++){
        while (!test[i].empty()) {
            delete test[i].back();  test[i].pop_back();
        }
    }
    test.clear();
    results.clear();
}

void MainWindow::solveProblems(){

    qint64 max = 0;
    int maxCut = 0;
    int maxJump = 0;
    results.clear();

    if(ui->enableCP->isChecked())
        sol.setCP(true);
    else
        sol.setCP(false);
    QProgressBar progress;
    progress.setMaximum(test.size()*ui->instancesForProblem->value());

    progress.show();
    for(int i = 0; i < test.size(); i++){
        float cpuTimeAvg = 0;
        float jumpsAvg = 0, cutsAvg = 0;
        for(int j = 0; j < test[i].size(); j++){
            Solution t_sol = sol.solveProblem(test.at(i).at(j));
            cpuTimeAvg += t_sol.getCpuTime();
            jumpsAvg += t_sol.getJumps();
            cutsAvg += t_sol.getCuts();
            if(j == test[i].size()-1){
                cpuTimeAvg = cpuTimeAvg/(j+1);
                jumpsAvg = jumpsAvg/(j+1);
                cutsAvg = cutsAvg/(j+1);
                t_sol.setCpuTime(cpuTimeAvg);
                t_sol.setJumps(jumpsAvg);
                t_sol.setCuts(cutsAvg);
                results.push_back(t_sol);
                if(cpuTimeAvg > max)
                    max = cpuTimeAvg;
                if(jumpsAvg > maxJump)
                    maxJump = jumpsAvg;
                if(cutsAvg > maxCut)
                    maxCut = cutsAvg;
            }
            progress.setValue(((i)*ui->instancesForProblem->value()+(j+1)));
        }

    }

    int steps = 0;
    if(ui->tighstep->isChecked())
        steps = ui->tightnessstep->value();
    else if(ui->denstep->isChecked())
        steps = ui->densitystep->value();

    GPlot * graph = new GPlot(ui->enableCP->isChecked(),steps,results,ui->denstep->isChecked(),ui->density->value(),ui->maxden->value(),ui->tighstep->isChecked(),ui->tightness->value(),ui->maxtigh->value(), max);
    QWidget * window = new QWidget();
    QHBoxLayout *layout = new QHBoxLayout( window );
    layout->setContentsMargins( 0, 0, 0, 0 );
    layout->addWidget( graph );
    window->resize(600,400);
    window->show();
    charts.push_back(window);

    graph = new GPlot(ui->enableCP->isChecked(),steps,results,ui->denstep->isChecked(),ui->density->value(),ui->maxden->value(),ui->tighstep->isChecked(),ui->tightness->value(),ui->maxtigh->value(), max, true, maxCut, maxJump);
    window = new QWidget();
    layout = new QHBoxLayout( window );
    layout->setContentsMargins( 0, 0, 0, 0 );
    layout->addWidget( graph );
    window->resize(600,400);
    window->show();
    charts.push_back(window);
}

void MainWindow::print(Problem * pm){
    QString pos = QString((QDate::currentDate().toString()))+".txt";
    QFile file(pos);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return;

    QTextStream out(&file);
    //Parameters
    out << "N " << pm->_pam.getN() << "\n";
    out << "M " << pm->_pam.getM() << "\n";
    out << "St " << pm->_pam.getSt() << "\n";
    out << "Sc " << pm->_pam.getSc() << "\n";
    out << "maxV " << pm->_pam.getMaxV() << "\n";

    out << "Variables "<< "\n";
    for(int i = 0; i < pm->variables.size(); i++){
        out << "Var "<< i << "\n";
        QMap<int, int>::const_iterator it = pm->variables[i].vals.constBegin();
        while(it != pm->variables[i].vals.constEnd()){
            out << " " << it.key() << " " << it.value() << "\n";
            ++it;
        }
    }
    out << "Constraints Tables" << "\n";
    QMap<QPair<int,int>,Link>::const_iterator it1 = pm->constraints.constBegin();
    while(it1 != pm->constraints.constEnd()){
        out << "Cons "<< it1.key().first << " " << it1.key().second << "\n";
        QMap<QPair<int,int>,int>::const_iterator it2 = it1.value().constraint_table.constBegin();
        while(it2 != it1.value().constraint_table.constEnd()){
            out << " " << it2.key().first << it2.key().second << " " << it2.value() << "\n";
            ++it2;
        }
        ++it1;
    }
    file.close();

}

void MainWindow::exit(){
    QApplication::exit(0);
}

MainWindow::~MainWindow()
{
    delete ui;
}
